const { join, dirname } = require('path');
const { Service, isAdminUser } = require('node-windows');
const winServiceConf = require('./config.service.json');
const productionConfig = require('./config.production.json');
const { rmdirSync } = require('fs');
const { execSync } = require('child_process');
const sudo = require('sudo-prompt');

const argsList = process.argv;

function main() {
    // 校验参数
    const status = validator();
    if (!status) return;
    console.log(argsList);
    handleServiceManger();
}

function validator() {
    if (argsList.length < 3) {
        printHelpInfo();
        return false;
    }

    return true;
}

function printHelpInfo() {
    console.log(
        `
    node ./service [操作类型] [参数]
    
    操作类型: 
        install 注册服务
        start 启动服务
        stop 停止服务
        restart 重启服务
        uninstall 注销服务

    参数类型: 
        --env   设置运行时环境变量
            node ./service start --env:db_name=test&username=root ...
        --max   设置自动重启最大重启次数
            node ./service install --max:9999
        --wait  设置每次重启的等待间隔[单位 s]
            node ./service install --wait:3
`,
    );
}

function handleServiceManger() {
    if (!winServiceConf) return console.err('service.production.json 无服务配置!!, 请配置启动信息');
    if (!isHasPermissions()) return console.err('无admin 权限!');

    const service = getService();

    handleOperate(service, argsList[2]);
}

function getService() {
    let nodeEnvList = [];
    if (productionConfig) {
        for (const [envKey, envValue] of Object.entries(productionConfig)) {
            nodeEnvList.push({
                name: envKey,
                value: envValue,
            });
        }
    }
    console.log(JSON.stringify(productionConfig, null, 4));

    // Create a new service object
    let svc = new Service({
        maxRestarts: 9999,
        maxRetries: 9999,
        grow: 0,
        wait: 2,
        ...winServiceConf,
        script: join(__dirname, `../${winServiceConf.script}`),
        env: nodeEnvList || [],
        allowServiceLogon: winServiceConf.allowServiceLogon,
    });

    if (winServiceConf.allowServiceLogon) {
        svc.logOnAs.account = winServiceConf.account;
        svc.logOnAs.password = winServiceConf.password;
    }

    return svc;
}

function isHasPermissions() {
    return new Promise((resolve, reject) => {
        try {
            isAdminUser((isAdmin) => {
                resolve(isAdmin);
            });
        } catch (error) {
            console.log(error);
            reject(error);
        }
    });
}

function handleOperate(svc, args) {
    // handle help
    if (args == '-h' || args == '--help') {
        printHelpInfo();
    }

    // 注册服务
    if (args === 'install') {
        svc.on('install', function () {
            svc.start();
            console.log(`${winServiceConf.name} 注册启动成功!`);
        });

        svc.install();
    }

    // 启动
    if (args === 'start') {
        svc.on('start', function () {
            console.log(`${winServiceConf.name} 启动完成!`);
        });

        return svc.start();
    }

    // 停止
    if (args === 'stop') {
        return svc.stop();
    }

    // 重启
    if (args === 'restart') {
        svc.stop();
        svc.on('stop', function () {
            svc.start();
        });
        svc.on('start', function () {
            console.log(`${winServiceConf.name} 启动完成!`);
        });
    }

    // 卸载
    if (args === 'uninstall') {
        svc.stop();
        svc.on('stop', async function () {
            // 注销
            try {
                await execPromoise(`sc delete ${winServiceConf.name}.exe`);
                // 删除daemon文件夹
                const script = join(__dirname, `../${winServiceConf.script}`);
                console.log(script);
                const daemonPath = join(script.slice(0, script.lastIndexOf('\\')), 'daemon');
                rmdirSync(daemonPath, { recursive: true });
                console.log(`${winServiceConf.name} 注销完成`);
            } catch (error) {
                console.log(error);
            }
        });
    }
}

var options = {
    name: 'Electron',
    icns: '/Applications/Electron.app/Contents/Resources/Electron.icns', // (optional)
};
async function execPromoise(cmd) {
    return new Promise((resolve, reject) => {
        sudo.exec(cmd, options, function (error, stdout, stderr) {
            if (error) return reject(error);

            if (stderr) return reject(stderr);

            resolve(stdout);
        });
    });
}

main();
